package com.sharesrc.umangadownloader.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.StyleInjector;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.sharesrc.umangadownloader.client.browse.IFBrowseService;
import com.sharesrc.umangadownloader.client.browse.IFBrowseServiceAsync;
import com.sharesrc.umangadownloader.client.content.ContentFactory;
import com.sharesrc.umangadownloader.shared.common.Constant.MangaSites;
import com.sharesrc.umangadownloader.shared.model.MangaDesc;
import com.sharesrc.umangadownloader.shared.model.MangaInfo;
import com.sharesrc.umangadownloader.shared.model.MangaSiteInfo;
import com.sharesrc.umangadownloader.shared.model.SitePageInfo;

public class U_Manga_Downloader implements EntryPoint {

	ListBox lstMangaSites, lstMangaInAlphabeticalOrder, lstAllManga;
	Label lblCount;
	TextBox tfCustomFilter, tfCurrentPage, tfLastPage;
	Button btnFirstPage, btnPreviousPage, btnNextPage, btnLastPage, btnGo;
	RadioButton rbSearchInSite, rbSearchOnlyInList;
	HTMLPanel pnlContent;

	private List<MangaSiteInfo> lstMangaSitesInfo;
	private HashMap<String, List<SitePageInfo>> hmapSitePagesInfo;
	private int currentPageIndex;

	private final IFBrowseServiceAsync browseService = GWT.create(IFBrowseService.class);

	private final EventsHandler handler = new EventsHandler();

	int getCurrentPageIndex() {
		return this.currentPageIndex;
	}

	private void setCurrentPageIndex(int currentPageIndex) {
		this.currentPageIndex = currentPageIndex;
	}

	@Override
	public void onModuleLoad() {
		this.lstMangaSitesInfo = new LinkedList<MangaSiteInfo>();
		this.hmapSitePagesInfo = new HashMap<String, List<SitePageInfo>>();
		this.currentPageIndex = 0;

		this.lstMangaSites = new ListBox();
		this.lstMangaSites.setVisibleItemCount(1);
		this.lstMangaSites.addItem("");
		for (MangaSites mangaSite : MangaSites.values()) {
			String id = mangaSite.getValue();
			this.lstMangaSites.addItem(id);
		}
		addSitePage("");
		this.lstMangaInAlphabeticalOrder = new ListBox();
		this.lstMangaInAlphabeticalOrder.setVisibleItemCount(1);
		this.lstMangaInAlphabeticalOrder.addItem("");
		this.lstMangaInAlphabeticalOrder.addItem("#");
		addSitePage("#");
		for (int i = 65; i < 91; i++) {
			String id = String.valueOf((char) i);
			this.lstMangaInAlphabeticalOrder.addItem(id);
			addSitePage(id);
		}
		this.tfCustomFilter = new TextBox();
		this.rbSearchInSite = new RadioButton("search-options", "In Site");
		this.rbSearchInSite.setValue(true);
		this.rbSearchOnlyInList = new RadioButton("search-options", "Only In List");
		this.lstAllManga = new ListBox();
		this.lstAllManga.setVisibleItemCount(2);
		this.lblCount = new Label("0");
		this.btnFirstPage = new Button("<<");
		this.btnPreviousPage = new Button("<");
		this.btnNextPage = new Button(">");
		this.btnLastPage = new Button(">>");
		this.tfCurrentPage = new TextBox();
		this.tfCurrentPage.setWidth("25px");
		this.tfCurrentPage.setText("0");
		this.tfLastPage = new TextBox();
		this.tfLastPage.setWidth("25px");
		this.tfLastPage.setEnabled(false);
		this.tfLastPage.setReadOnly(true);
		this.tfLastPage.setText("0");
		this.btnGo = new Button("Go");
		this.pnlContent = new HTMLPanel("");
//		this.pnlContent = new HTMLPanel(ContentFactory.INSTANCE.getResources().intro().getText());

		RootPanel.get("lstMangaSites").add(this.lstMangaSites);
		RootPanel.get("lstMangaInAlphabeticalOrder").add(this.lstMangaInAlphabeticalOrder);
		RootPanel.get("tfCustomFilter").add(this.tfCustomFilter);
		RootPanel.get("rbSearchInSite").add(this.rbSearchInSite);
		RootPanel.get("rbSearchOnlyInList").add(this.rbSearchOnlyInList);
		RootPanel.get("lstAllManga").add(this.lstAllManga);
		RootPanel.get("lblCount").add(this.lblCount);
		RootPanel.get("btnFirstPage").add(this.btnFirstPage);
		RootPanel.get("btnPreviousPage").add(this.btnPreviousPage);
		RootPanel.get("tfCurrentPage").add(this.tfCurrentPage);
		RootPanel.get("tfLastPage").add(this.tfLastPage);
		RootPanel.get("btnNextPage").add(this.btnNextPage);
		RootPanel.get("btnLastPage").add(this.btnLastPage);
		RootPanel.get("btnGo").add(this.btnGo);
		RootPanel.get("content").add(this.pnlContent);

		this.lstMangaSites.addChangeHandler(this.handler);
		this.lstMangaInAlphabeticalOrder.addChangeHandler(this.handler);
		this.lstAllManga.addClickHandler(this.handler);
		this.lstAllManga.addDoubleClickHandler(this.handler);
		this.btnFirstPage.addClickHandler(this.handler);
		this.btnPreviousPage.addClickHandler(this.handler);
		this.btnNextPage.addClickHandler(this.handler);
		this.btnLastPage.addClickHandler(this.handler);
		this.btnGo.addClickHandler(this.handler);
	}

	private void addSitePage(String childSiteId) {
		for (MangaSites mangaSite : MangaSites.values()) {
			String siteName = mangaSite.getValue();
			String siteId = siteName + (childSiteId.length() == 0 ? "" : ("/" + childSiteId));
			this.lstMangaSitesInfo.add(new MangaSiteInfo(siteName, childSiteId));
			this.hmapSitePagesInfo.put(siteId, new ArrayList<SitePageInfo>());
		}
	}

	boolean isSiteUpdated(String siteName, String childSiteId) {
		for (MangaSiteInfo site : this.lstMangaSitesInfo) {
			if (site.getName().equals(siteName) && site.getChildSiteId().equals(childSiteId) && site.getMangaCount() > 0) {
				return true;
			}
		}
		return false;
	}

	private void updateLstMangaSitesInfo(MangaSiteInfo newInfo) {
		for (MangaSiteInfo info : this.lstMangaSitesInfo) {
			if (info.getName().equals(newInfo.getName()) && info.getChildSiteId().equals(newInfo.getChildSiteId())) {
				info.setId(newInfo.getId());
				info.setPageCount(newInfo.getPageCount());
				info.setMangaCount(newInfo.getMangaCount());
				for (int i = 0; i < info.getPageCount(); i++) {
					info.getLstIsPageUpdated().add(Boolean.FALSE);
				}
			}
		}
	}

	boolean isSitePageUpdated(String siteName, String childSiteId, String pageIndex) {
		for (MangaSiteInfo site : this.lstMangaSitesInfo) {
			if (site.getName().equals(siteName) && site.getChildSiteId().equals(childSiteId)) {
				try {
					return site.getLstIsPageUpdated().get(Integer.parseInt(pageIndex) - 1).booleanValue();
				} catch (IndexOutOfBoundsException e) {
					return false;
				}
			}
		}
		return false;
	}

	private void setSitePageUpdated(String siteName, String childSiteId, String pageIndex) {
		for (MangaSiteInfo site : this.lstMangaSitesInfo) {
			if (site.getName().equals(siteName) && site.getChildSiteId().equals(childSiteId)) {
				site.setPageUpdated(Integer.parseInt(pageIndex) - 1);
			}
		}
	}

	MangaSiteInfo getSiteInfo(String siteName, String childSiteId) {
		for (MangaSiteInfo site : this.lstMangaSitesInfo) {
			if (site.getName().equals(siteName) && site.getChildSiteId().equals(childSiteId)) {
				return site;
			}
		}
		return null;
	}

	MangaInfo getMangaInfo(String siteId, int selectedIndex) {
		List<SitePageInfo> allPages = this.hmapSitePagesInfo.get(siteId);
		for (SitePageInfo page : allPages) {
			int idx = getCurrentPageIndex();
			if (page.getIndex() == idx) {
				return page.getLstMangaInfo().get(selectedIndex);
			}
		}
		return null;
	}

	void getMangaDesc(int selectedIndex) {
		String siteName = this.lstMangaSites.getItemText(this.lstMangaSites.getSelectedIndex());
		String childSiteId = this.lstMangaInAlphabeticalOrder.getItemText(this.lstMangaInAlphabeticalOrder.getSelectedIndex());
		String siteId = siteName + (childSiteId.length() == 0 ? "" : ("/" + childSiteId));
		MangaInfo info = getMangaInfo(siteId, selectedIndex);
		this.browseService.getMangaDesciption(siteName, info.getLink(), new AsyncCallback<MangaDesc>() {

			@Override
			public void onSuccess(MangaDesc result) {
				ContentFactory.INSTANCE.getResources().css().ensureInjected();
				RootPanel.get("content").clear();
				RootPanel.get("content").add(new HTML("<div align='center'> <h1 id='testId'>Introduction!!!</h1></div>"));
//				StyleInjector.inject(ContentFactory.INSTANCE.getResources().css().getText());
//				pnlContent.getElement().setInnerHTML("<div align='center'> <h1 id='testId'>Introduction NEW!!!</h1></div>");
			}

			@Override
			public void onFailure(Throwable caught) {

			}
		});
	}

	private void updateHmapSitePagesInfo(String siteId, SitePageInfo newInfo) {
		List<SitePageInfo> lstSitePages = this.hmapSitePagesInfo.get(siteId);
		if (!lstSitePages.contains(newInfo)) {
			lstSitePages.add(newInfo);
		}
	}

	void refreshAll() {
		clearAll();
		setCurrentPageIndex(1);

		int selectedSiteIdx = this.lstMangaSites.getSelectedIndex();
		if (selectedSiteIdx <= 0) {
			return;
		}
		String siteName = this.lstMangaSites.getItemText(selectedSiteIdx);
		String childSiteId = "", pageIndex = "1";
		int selectedChildSiteIdx = this.lstMangaInAlphabeticalOrder.getSelectedIndex();
		if (selectedChildSiteIdx > 0) {
			childSiteId = this.lstMangaInAlphabeticalOrder.getItemText(selectedChildSiteIdx);
		}
		if (!isSitePageUpdated(siteName, childSiteId, pageIndex)) {
			getMangaSiteInfo(siteName, childSiteId);
		} else {
			refreshListAllManga(siteName, childSiteId, pageIndex);
		}
	}

	void refreshListMangaPage() {
		this.lstAllManga.clear();
		String siteName = this.lstMangaSites.getItemText(this.lstMangaSites.getSelectedIndex() == -1 ? 0 : this.lstMangaSites.getSelectedIndex());
		String childSiteId = this.lstMangaInAlphabeticalOrder.getItemText(this.lstMangaInAlphabeticalOrder.getSelectedIndex() == -1 ? 0 : this.lstMangaInAlphabeticalOrder.getSelectedIndex());
		String pageIndex = this.tfCurrentPage.getText().trim();
		if (!isSitePageUpdated(siteName, childSiteId, pageIndex)) {
			getSitePageInfo(siteName, childSiteId, pageIndex);
		} else {
			refreshListAllManga(siteName, childSiteId, pageIndex);
		}
	}

	void clearAll() {
		this.lblCount.setText("0");
		this.tfCurrentPage.setText("0");
		this.tfLastPage.setText("0");
		this.lstAllManga.clear();
	}

	void refreshListAllManga(String siteName, String childSiteId, String pageIndex) {
		if (Integer.parseInt(pageIndex) < getCurrentPageIndex()) {
			return;
		}
		String siteId = siteName + (childSiteId.length() == 0 ? "" : ("/" + childSiteId));
		MangaSiteInfo site = getSiteInfo(siteName, childSiteId);
		this.lblCount.setText(String.valueOf(site.getMangaCount()));
		this.tfCurrentPage.setText(pageIndex);
		this.tfLastPage.setText(String.valueOf(site.getPageCount()));
		for (String key : this.hmapSitePagesInfo.keySet()) {
			if (siteId.equals(key)) {
				for (SitePageInfo page : this.hmapSitePagesInfo.get(key)) {
					if (page.getIndex() == Integer.parseInt(pageIndex)) {
						List<MangaInfo> allManga = page.getLstMangaInfo();
						for (MangaInfo manga : allManga) {
							this.lstAllManga.addItem(manga.getDisplayName());
						}
					}
				}
			}
		}
	}

	private void getMangaSiteInfo(final String siteName, final String childSiteId) {
		if (!isSiteUpdated(siteName, childSiteId)) {
			this.browseService.getMangaSiteInfo(siteName, childSiteId, new AsyncCallback<MangaSiteInfo>() {

				@Override
				public void onSuccess(MangaSiteInfo result) {
					if (result == null) {
						return;
					}
					updateLstMangaSitesInfo(result);
					getSitePageInfo(siteName, childSiteId, "1");
				}

				@Override
				public void onFailure(Throwable caught) {

				}
			});
		} else {
			getSitePageInfo(siteName, childSiteId, "1");
		}
	}

	private void getSitePageInfo(final String siteName, final String childSiteId, final String pageIndex) {
		if (siteName.length() == 0) {
			return;
		}
		this.browseService.getSitePageInfo(siteName, childSiteId, pageIndex, new AsyncCallback<SitePageInfo>() {

			@Override
			public void onSuccess(SitePageInfo result) {
				if (result == null) {
					return;
				}
				String siteId = siteName + (childSiteId.length() == 0 ? "" : ("/" + childSiteId));
				updateHmapSitePagesInfo(siteId, result);
				setSitePageUpdated(siteName, childSiteId, pageIndex);
				refreshListAllManga(siteName, childSiteId, pageIndex);
			}

			@Override
			public void onFailure(Throwable caught) {

			}
		});
	}

	boolean isValidPageIndex() {
		try {
			String lastPageStr = this.tfLastPage.getText().toString().trim();
			int lastPage = Integer.parseInt(lastPageStr);
			if (lastPage == 0) {
				return false;
			}
			String currentPageStr = this.tfCurrentPage.getText().toString().trim();
			int currentPage = Integer.parseInt(currentPageStr);
			if (currentPage < 1 || currentPage > lastPage) {
				return false;
			}
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	private void updateCurrentPage(int currentPage) {
		this.tfCurrentPage.setText(String.valueOf(currentPage));
		setCurrentPageIndex(currentPage);
		refreshListMangaPage();
	}

	class EventsHandler implements ChangeHandler, ClickHandler, DoubleClickHandler {

		@Override
		public void onChange(ChangeEvent event) {
			if (event.getSource().equals(U_Manga_Downloader.this.lstMangaSites) || event.getSource().equals(U_Manga_Downloader.this.lstMangaInAlphabeticalOrder)) {
				refreshAll();
			}
		}

		@Override
		public void onClick(ClickEvent event) {
			if (event.getSource().equals(U_Manga_Downloader.this.lstAllManga)) {

			}
			if (event.getSource().equals(U_Manga_Downloader.this.btnFirstPage)) {
				if (!isValidPageIndex()) {
					return;
				}
				updateCurrentPage(1);
			}
			if (event.getSource().equals(U_Manga_Downloader.this.btnPreviousPage)) {
				if (!isValidPageIndex()) {
					return;
				}
				int currentPage = Integer.parseInt(U_Manga_Downloader.this.tfCurrentPage.getText().trim());
				if (--currentPage < 1) {
					return;
				}
				updateCurrentPage(currentPage);
			}
			if (event.getSource().equals(U_Manga_Downloader.this.btnNextPage)) {
				if (!isValidPageIndex()) {
					return;
				}
				int currentPage = Integer.parseInt(U_Manga_Downloader.this.tfCurrentPage.getText().trim());
				int lastPage = Integer.parseInt(U_Manga_Downloader.this.tfLastPage.getText().trim());
				if (++currentPage > lastPage) {
					return;
				}
				updateCurrentPage(currentPage);
			}
			if (event.getSource().equals(U_Manga_Downloader.this.btnLastPage)) {
				if (!isValidPageIndex()) {
					return;
				}
				int lastPage = Integer.parseInt(U_Manga_Downloader.this.tfLastPage.getText().trim());
				updateCurrentPage(lastPage);
			}
			if (event.getSource().equals(U_Manga_Downloader.this.btnGo)) {
				if (!isValidPageIndex()) {
					return;
				}
				int currentPage = Integer.parseInt(U_Manga_Downloader.this.tfCurrentPage.getText().trim());
				if (currentPage != getCurrentPageIndex()) {
					updateCurrentPage(currentPage);
				}
			}
		}

		@Override
		public void onDoubleClick(DoubleClickEvent event) {
			if (event.getSource().equals(U_Manga_Downloader.this.lstAllManga)) {
				int selectedIdx = U_Manga_Downloader.this.lstAllManga.getSelectedIndex();
				if (selectedIdx == -1) {
					return;
				}
				getMangaDesc(selectedIdx);
			}
		}
	}
}
